home *** CD-ROM | disk | FTP | other *** search
- Hello Xboing fans,
-
- This is a patch for version 2.4 of XBoing. A cool bloke called Alexander
- sent me this patch which helps to fix the game speed problem. His email is
- below followed by the patch. Just cut the patch code out and apply this
- to the source for xboing2.4
-
- Good luck.
-
- PS: Don't forget to cut off my sig at the end of the patch!
-
- email message from Alexander :-
-
- I guess as a result of some confusion, SleepSync() invokes usleep()
- with the parameter of milliseconds, while BSD usleep() implemented in
- all the OS I am aware of requires microseconds. Moreover, the
- internally generated usleep() accepts milliseconds in one compilation
- instance and microseconds in another.
-
- Xboing 2.3 didn't sleep at all (except for the "SLOW_SPEED" game
- mode), so the frame rate was totally defined by the processor power
- while the variation of game speed was induced by the ball velocity
- changing in accordance with the "speedLevel".
-
- There is some improvement in Xboing 2.4. Now the SleepSync()
- accumulates the required sleeping time up until it exceeds 33.33 ms.
- For the default warp factor (5) it results in 6 frames being passed
- without delay followed by the invocation of usleep( 35 ) after the
- 7th.
-
- As no OS is capable to put a process asleep for a few microseconds due
- to the overheads involved in context switching, Linux (and I suspect
- the other OS too) uses a threshold resolution - the process is
- suspended until the next tick of the PSU timer, something like 20 or
- 16.66 ms.
-
- So somehow it works due to combination of bugs and the current
- technology limitations. However, no influence on the frame rate was
- achieved, the sleeping time does not depend on the parameter of
- usleep() (as long as it remains relatively small) but it depends on
- the phase of internal frame progress. This can result in a significant
- drop in the game speed if the processor is not fast enough meaning
- that 7 frames can not be processed within the timer resolution (16.66
- ms). Correcting this bug won't help: If you replaced usleep( 35 ) by
- usleep( 35*1000 ) the game would be ridiculously slow.
-
- As it seems to me, the adequate solution is to synchronise the frame
- progress with the real time, i.e. to stabilise the frame rate at a
- particular level regardless of the processor power. The traces of such
- an attempt can be found in SleepSync(): the time taken by XSynch is
- taken out of the sleeping time.
-
- In the patch attached to this letter, SleepSync() is replaced by a
- simple FLL/PLL timer stabilising the frame rate according to its "ms"
- parameter (so it is 5ms/frame as a default). Because the both, the
- frame rate and the ball velocity are involved, I reduced the range of
- "userDelay" (see patch for "main.c"). Maybe it requires further
- reduction. Also the timings in "bonus.c" and "presents.c" were
- adjusted. Due to the real-time frame rates, they can now be calculated
- much more precisely.
-
- Regards,
- ---
- Alex Bolychevsky | voice: +44-1483-259000 x 2384
- Dept of Electronic & Electrical Eng., | fax: +44-1483-34139
- University of Surrey, | telex: 859331 UNIVSY G
- Guildford, GU2 5XH, United Kingdom | e-mail: a.bolychevsky@ee.surrey.ac.uk
-
- ------------------------ >8 ---- CUT HERE ---- 8< --------------------------
- diff -u --recursive xboing/bonus.c xbpatch/bonus.c
- --- xboing/bonus.c Fri Nov 22 01:28:46 1996
- +++ xbpatch/bonus.c Tue Jan 14 18:48:28 1997
- @@ -311,7 +311,7 @@
- XFlush(display);
-
- SetBonusWait(BONUS_SCORE, frame + 5);
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- DEBUG("set bonus mode to BONUS_SCORE.")
- }
- @@ -326,7 +326,7 @@
- {
- DEBUG("in function DoScore() in bonus.c")
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Nice message rewarding you for your efforts */
- strcpy(string, "Congratulations on finishing this level.");
- @@ -336,7 +336,7 @@
-
- ypos += (35 + GAP);
- SetBonusWait(BONUS_BONUS, frame + LINE_DELAY);
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
- DEBUG("set bonus mode to BONUS_BONUS.")
- }
-
- @@ -363,7 +363,7 @@
- DrawShadowCentredText(display, window, textFont,
- string, ypos, blue, TOTAL_WIDTH);
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Now skip to the next sequence */
- SetBonusWait(BONUS_LEVEL, frame + LINE_DELAY);
- @@ -387,7 +387,7 @@
- DrawShadowCentredText(display, window, textFont,
- string, ypos, blue, TOTAL_WIDTH);
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Now skip to the next sequence */
- SetBonusWait(BONUS_LEVEL, frame + LINE_DELAY);
- @@ -411,7 +411,7 @@
- bonusScore += ComputeScore(SUPER_BONUS_SCORE);
- DisplayScore(display, scoreWindow, bonusScore);
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Now skip to the next sequence */
- SetBonusWait(BONUS_LEVEL, frame + LINE_DELAY);
- @@ -454,7 +454,7 @@
- ypos += (int) (textFont->ascent + GAP * 1.5);
- firstTime = True;
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
- }
- }
-
- @@ -468,7 +468,7 @@
- {
- int secs, theLevel;
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Get the number of seconds left on the clock */
- secs = GetLevelTimeBonus();
- @@ -533,7 +533,7 @@
- /* Play the sound for the super bonus */
- if (noSound == False) playSoundFile("Doh3", 80);
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Get ready for the next sequence */
- SetBonusWait(BONUS_TIME, frame + LINE_DELAY);
- @@ -569,7 +569,7 @@
- SetBonusWait(BONUS_TIME, frame + LINE_DELAY);
- ypos += (textFont->ascent + GAP/2);
- firstTime = True;
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
- }
- }
-
- @@ -583,7 +583,7 @@
- {
- int secs = 0;
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Get the number of seconds left on the clock */
- secs = GetLevelTimeBonus();
- @@ -627,7 +627,7 @@
- int myrank = 0;
- char str[5];
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Obtain current ranking for this score */
- myrank = GetHighScoreRanking(score);
- @@ -680,7 +680,7 @@
- {
- DEBUG("DoEndText in bonus screen.")
-
- - SetGameSpeed(SLOW_SPEED);
- + SetGameSpeed(MEDIUM_SPEED);
-
- /* Finishing sentence - so you know what level to do */
- sprintf(string, "Prepare for level %ld", level+1);
- diff -u --recursive xboing/main.c xbpatch/main.c
- --- xboing/main.c Fri Nov 22 01:28:46 1996
- +++ xbpatch/main.c Tue Jan 14 18:32:30 1997
- @@ -156,7 +156,7 @@
-
- /* Set an entire game speedup or slowdown speed */
- temp = (speed / (long) userDelay);
- - userDelay = delay;
- + userDelay = delay/2 + 3;
- speed = (long) (temp * userDelay);
- speedLevel = 10 - delay;
- }
- diff -u --recursive xboing/misc.c xbpatch/misc.c
- --- xboing/misc.c Fri Nov 22 01:28:46 1996
- +++ xbpatch/misc.c Tue Jan 14 18:54:45 1997
- @@ -89,8 +89,8 @@
- #ifdef SYSV
- #ifdef __clipper__
- struct timeval tv;
- - tv.tv_sec=((usec)/1000);
- - tv.tv_usec=(((usec)%1000)*1000);
- + tv.tv_sec=((usec)/1000000);
- + tv.tv_usec=((usec)%1000000);
- select(1,NULL,NULL,NULL,&tv);
- #else
- poll((struct poll *) 0, (size_t) 0, usec / 1000); /* ms resolution */
- @@ -105,6 +105,68 @@
- #endif
-
- #if NeedFunctionPrototypes
- +static int kudelay(unsigned long count)
- +#else
- +static int kudelay(count)
- +unsigned long count;
- +#endif
- +{
- + unsigned int bluff = 1;
- +
- + while( count-- != 0 ) /* this can hardly be "optimised out" */
- + bluff = (bluff ^ ((bluff & 1) * 0x6110)) >> 1;
- +
- + return( bluff );
- +}
- +
- +#if NeedFunctionPrototypes
- +static void kusleep(unsigned long usec)
- +#else
- +static void kusleep(usec)
- + unsigned long usec;
- +#endif
- +{
- + static float kuliber_time = 0.0;
- + static float kuliber_count = 0.0;
- + static unsigned long kutimerswap = (1000000 / 15);
- + struct timeval st, et;
- + long gap;
- + unsigned long count;
- +
- + if( kuliber_time == 0.0 )
- + {
- + count = 0x1000; /* calibrate delay loop */
- + gettimeofday(&st, NULL);
- +
- + while( True )
- + {
- + kudelay( count );
- + count = (count << 1);
- + gettimeofday(&et, NULL);
- + gap = (((et.tv_sec - st.tv_sec) * 1000000) +
- + (et.tv_usec - st.tv_usec) );
- +
- + if( gap > 400*1000 )
- + break;
- + }
- +
- + kuliber_time = (float)(gap/4);
- + kuliber_count = (float)(((count-1)&~0xFFF)>>2);
- + }
- +
- + if( usec > kutimerswap )
- + {
- + kutimerswap = (1000000 / 30);
- + usleep( usec ); /* using usleep() for low resolution only */
- + }
- + else
- + {
- + kutimerswap = (1000000 / 15);
- + kudelay( (unsigned long)(kuliber_count*((float)usec/kuliber_time)) );
- + }
- +}
- +
- +#if NeedFunctionPrototypes
- void sleepSync(Display *display, unsigned long ms)
- #else
- void sleepSync(display, ms)
- @@ -112,27 +174,85 @@
- unsigned long ms;
- #endif
- {
- - struct timeval st, et;
- - long SyncTime;
- - static unsigned long accu;
- + static long Expected_time = 0;
- + static long Ref_sec = 0;
- + static long Ref_usec = 0;
- + static long Sleeping_time = 0;
- + static int PLL_filter = 0;
- + struct timeval st;
- + long elapsed;
- + long dodelay;
- + float x;
-
- - gettimeofday(&st, NULL);
- XSync(display, False);
- - gettimeofday(&et, NULL);
-
- - SyncTime = (((et.tv_sec - st.tv_sec) * 1000) +
- - ((et.tv_usec - st.tv_usec) / 1000) );
- + gettimeofday(&st, NULL);
- +
- + if( Ref_sec == 0 )
- + {
- + Ref_sec = st.tv_sec; /* take the initial reference point */
- + Ref_usec = st.tv_usec;
- + Sleeping_time = ms * 1000;
- + }
- +
- + elapsed = (st.tv_sec - Ref_sec) * 1000000 + (st.tv_usec - Ref_usec);
- + dodelay = Sleeping_time;
- +
- + if( PLL_filter > 0 && elapsed != 0 ) /* Phase lock loop */
- + {
- + dodelay = Expected_time + Sleeping_time - elapsed;
- +
- + if( dodelay < 0 )
- + {
- + dodelay = 0; PLL_filter--;
- + }
- + else
- + if( dodelay > 2*Sleeping_time )
- + {
- + dodelay = 2*Sleeping_time; PLL_filter--;
- + }
- + else
- + PLL_filter = 3;
- +
- + if( elapsed > 40*Sleeping_time && Expected_time > 40*Sleeping_time )
- + {
- + elapsed -= 20*Sleeping_time; /* Ref. point shouldn't be far away*/
- + Expected_time -= 20*Sleeping_time;
- + Ref_usec += 20*Sleeping_time;
- + Ref_sec += Ref_usec/1000000; Ref_usec %= 1000000;
- + }
- + }
-
- -/* if ((ms) > ((1000 / 60) + SyncTime))
- - usleep(ms - SyncTime);
- -*/
- - if ((ms + accu) > ((1000 / 30) + SyncTime))
- + if( PLL_filter <= 0 && elapsed > 40000 ) /* Frequency lock loop */
- {
- - usleep(ms +accu - SyncTime);
- - accu = 0;
- + /* feedback filter */
- + x = 0.5 + 0.5 * (float)Expected_time / (float)elapsed;
- +
- + if( x < 0.966 ) /* Acceleration must be strongly limited */
- + x = 0.966;
- +
- + if( x > 2.0 )
- + x = 2.0;
- +
- + Sleeping_time = (long)((float)Sleeping_time * x);
- +
- + if( Sleeping_time < 500 )
- + Sleeping_time = 500;
- +
- + if( x > 0.99 && x < 1.01 && Sleeping_time > ms*500 )
- + PLL_filter = -1 - 4*PLL_filter; /* locked - it's time to try PLL */
- + else
- + PLL_filter = 0;
- +
- + Ref_sec = st.tv_sec;
- + Ref_usec = st.tv_usec;
- + Expected_time = 0;
- + dodelay = Sleeping_time;
- }
- - else if (ms > SyncTime)
- - accu += (ms - SyncTime);
- +
- + kusleep( dodelay );
- +
- + Expected_time += ms * 1000;
- }
-
- #if NeedFunctionPrototypes
- diff -u --recursive xboing/presents.c xbpatch/presents.c
- --- xboing/presents.c Fri Nov 22 01:28:46 1996
- +++ xbpatch/presents.c Tue Jan 14 18:35:40 1997
- @@ -287,7 +287,7 @@
- }
- #endif
-
- - SetPresentWait(PRESENT_TEXT1, frame + 800);
- + SetPresentWait(PRESENT_TEXT1, frame + 200);
- }
-
- #if NeedFunctionPrototypes
- @@ -309,7 +309,7 @@
- RenderShape(display, window, justin, justinM,
- x, y, 285, 44, True);
-
- - SetPresentWait(PRESENT_TEXT2, frame + 300);
- + SetPresentWait(PRESENT_TEXT2, frame + 100);
- }
-
- #if NeedFunctionPrototypes
- @@ -331,7 +331,7 @@
- RenderShape(display, window, kibell, kibellM,
- x, y, 260, 40, True);
-
- - SetPresentWait(PRESENT_TEXT3, frame + 500);
- + SetPresentWait(PRESENT_TEXT3, frame + 200);
- }
-
- #if NeedFunctionPrototypes
- @@ -355,7 +355,7 @@
- RenderShape(display, window, presents, presentsM,
- x, y, 410, 44, True);
-
- - SetPresentWait(PRESENT_TEXT_CLEAR, frame + 750);
- + SetPresentWait(PRESENT_TEXT_CLEAR, frame + 250);
- }
-
- #if NeedFunctionPrototypes
- @@ -375,7 +375,7 @@
-
- FadeAwayArea(display, window, x, y, 410, 44);
-
- - SetPresentWait(PRESENT_LETTERS, frame + 10);
- + SetPresentWait(PRESENT_LETTERS, frame + 5);
- }
-
- /* The distances for the gap inbetwen blocks */
- @@ -404,7 +404,7 @@
- DrawLetter(display, window, i, x, y);
- x += 10 + dists[i];
-
- - SetPresentWait(PRESENT_LETTERS, frame + 300);
- + SetPresentWait(PRESENT_LETTERS, frame + 100);
- }
- else
- {
- @@ -416,7 +416,7 @@
- x += dists[3];
- DrawLetter(display, window, 3, x, y);
-
- - SetPresentWait(PRESENT_SHINE, frame + 200);
- + SetPresentWait(PRESENT_SHINE, frame + 100);
- }
-
- i++;
- @@ -463,7 +463,7 @@
- if (in == 11)
- {
- XCopyArea(display, store, window, gc, 0, 0, 20, 20, x, y);
- - SetPresentWait(PRESENT_SPECIAL_TEXT1, frame + 500);
- + SetPresentWait(PRESENT_SPECIAL_TEXT1, frame + 100);
- }
- }
- }
- @@ -499,7 +499,7 @@
- len = strlen(wisdom);
- x = ((PLAY_WIDTH + MAIN_WIDTH) / 2) -
- (XTextWidth(dataFont, wisdom, len) / 2);
- - nextFrame = frame + 10;
- + nextFrame = frame + 5;
- first = False;
- }
-
- @@ -508,11 +508,11 @@
- if (noSound == False) playSoundFile("key", 60);
- DrawText(display, window, x, y, dataFont, red, wisdom, i);
-
- - nextFrame = frame + 30;
- + nextFrame = frame + 15;
-
- i++;
- if (i > len)
- - SetPresentWait(PRESENT_SPECIAL_TEXT2, frame + 700);
- + SetPresentWait(PRESENT_SPECIAL_TEXT2, frame + 150);
- }
- }
-
- @@ -542,7 +542,7 @@
- len = strlen(wisdom2);
- x = ((PLAY_WIDTH + MAIN_WIDTH) / 2) -
- (XTextWidth(dataFont, wisdom2, len) / 2);
- - nextFrame = frame + 10;
- + nextFrame = frame + 5;
- first = False;
- }
-
- @@ -551,11 +551,11 @@
- if (noSound == False) playSoundFile("key", 60);
- DrawText(display, window, x, y, dataFont, red, wisdom2, i);
-
- - nextFrame = frame + 30;
- + nextFrame = frame + 15;
-
- i++;
- if (i > len)
- - SetPresentWait(PRESENT_SPECIAL_TEXT3, frame + 700);
- + SetPresentWait(PRESENT_SPECIAL_TEXT3, frame + 150);
- }
- }
-
- @@ -584,7 +584,7 @@
- len = strlen(wisdom3);
- x = ((PLAY_WIDTH + MAIN_WIDTH) / 2) -
- (XTextWidth(dataFont, wisdom3, len) / 2);
- - nextFrame = frame + 10;
- + nextFrame = frame + 5;
- first = False;
- }
-
- @@ -593,11 +593,11 @@
- if (noSound == False) playSoundFile("key", 60);
- DrawText(display, window, x, y, dataFont, red, wisdom3, i);
-
- - nextFrame = frame + 30;
- + nextFrame = frame + 15;
-
- i++;
- if (i > len)
- - SetPresentWait(PRESENT_CLEAR, frame + 800);
- + SetPresentWait(PRESENT_CLEAR, frame + 200);
- }
- }
-
- @@ -642,7 +642,7 @@
- yb -= 10;
-
- if (yt > ((PLAY_HEIGHT + MAIN_HEIGHT) / 2))
- - SetPresentWait(PRESENT_FINISH, frame + 20);
- + SetPresentWait(PRESENT_FINISH, frame + 10);
-
- nextFrame = frame + 20;
- }
-
- ------------------------ >8 ---- CUT HERE ---- 8< --------------------------
-
- Cheers
-
- Justin Kibell - UNIX Administrator - RMIT Comm. Eng. - rcojk@co.rmit.edu.au
- Ph: 9282 2456 - System Administrator - RMIT C.A.T.T. - jck@catt.rmit.edu.au
-